#pragma once

#include <vector>
#include <queue>
#include <iostream>
#include "lockGuard.hpp"
#include "Thread.hpp"
#include "log.hpp"
#include "Task.hpp"

const int g_thread_num = 3;

template <class T>
class ThreadPool
{
public:
    pthread_mutex_t *getMutex()
    {
        return &lock;
    }

    bool isEmpty()
    {
        return task_queue_.empty();
    }

    void waitCond()
    {
        pthread_cond_wait(&cond, &lock);
    }

    T getTask()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }

    void run()
    {
        for(auto &it:threads_)
        {
            it->start();
            logMessage(NORMAL,"%s %s",it->name().c_str(),"启动成功");
        }
    }
    static void *routine(void *args)
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T>* tp = (ThreadPool<T>*)td->args_;
        
        while(true)
        {
            T task;
            {
                lockGuard lockguard(tp->getMutex());
                while(tp->isEmpty())
                    tp->waitCond();
                task = tp->getTask();
            }
            task(td->name_);
        }
    }

    void pushTask(const T& task)
    {
        lockGuard lg(&lock);
        task_queue_.push(task);
        pthread_cond_signal(&cond);
    }

    ~ThreadPool()
    {
        for (auto &it : threads_)
        {
            it->join();
            delete it;
        }

        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

    static ThreadPool<T>* getThreadPool(int thread_num)
    {
        if(thread_ptr == nullptr)
        {
            mutex.lock();
            if(nullptr == thread_ptr)
            {
                thread_ptr = new ThreadPool<T>(thread_num);
            }
            mutex.unlock();
        }
        return thread_ptr;
    }
private:
    ThreadPool(int thread_num = g_thread_num)
        : num_(thread_num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);

        for (int i = 1; i <= num_; i++)
        {
            threads_.push_back(new Thread(i, routine, this));
        }
    }

    

private:
    std::vector<Thread *> threads_;
    int num_;
    std::queue<T> task_queue_;
    pthread_mutex_t lock;
    pthread_cond_t cond;

    static ThreadPool<T>* thread_ptr;
    static pthread_mutex_t mutex;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::thread_ptr = nullptr;

template<class T>
pthread_mutex_t ThreadPool<T>::mutex=PTHREAD_MUTEX_INITIALIZER;